package com.gitee.yannzh.rune.support.crud.base;

import com.gitee.yannzh.rune.core.base.pojo.Entity;
import com.gitee.yannzh.rune.core.base.pojo.Param;
import com.gitee.yannzh.rune.core.base.vo.Result;
import com.gitee.yannzh.rune.core.util.ValidationUtils;
import com.gitee.yannzh.rune.support.crud.CrudHelper;
import com.gitee.yannzh.rune.support.crud.WebUtil;
import com.gitee.yannzh.rune.support.crud.annotation.Api;
import com.gitee.yannzh.rune.support.crud.constants.ApiMethod;
import lombok.Setter;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;

import javax.servlet.http.HttpServletRequest;
import javax.validation.constraints.NotEmpty;
import java.io.Serializable;
import java.util.Collection;
import java.util.function.Supplier;

/**
 * @author Yann
 * @date 2024/9/21 17:46
 * @description
 * @since 1.0.0
 */
public class CrudControllerProxy<T extends Entity, P extends Param> {

    protected final Class<T> entityType;

    protected final Class<?> handlerClass;

    @Setter
    protected Class<P> defaultParamType;

    @Setter
    protected Class<P> queryParamType;

    @Setter
    protected Class<P> saveParamType;

    @Setter
    protected Class<P> updateParamType;

    public CrudControllerProxy(Class<?> handlerClass, Class<T> entityType,
                               Class<P> defaultParamType) {
        this.handlerClass = handlerClass;
        this.entityType = entityType;
        this.defaultParamType = defaultParamType;
        this.saveParamType = defaultParamType;
        this.queryParamType = defaultParamType;
        this.updateParamType = defaultParamType;
    }


    @Api(value = ApiMethod.GET)
    @ResponseBody
    public Result<?> get(HttpServletRequest request) {
        return Result.ok(getService().get(getParams(request, this::getQueryParamType)));
    }

    @Api(value = ApiMethod.PAGE)
    @ResponseBody
    public Result<?> page(HttpServletRequest request) {
        return Result.ok(getService().pageList(getParams(request, this::getQueryParamType)));
    }

    @Api(value = ApiMethod.LIST)
    @ResponseBody
    public Result<?> list(HttpServletRequest request) {
        return Result.ok(getService().find(getParams(request, this::getQueryParamType)));
    }


    @Api(value = ApiMethod.SAVE, method = RequestMethod.POST)
    @ResponseBody
    public Result<?> save(HttpServletRequest request) {
        return Result.ok(getService().save(this.getParams(request, this::getSaveParamType)));
    }

    @Api(value = ApiMethod.UPDATE, method = RequestMethod.POST)
    @ResponseBody
    public Result<?> update(HttpServletRequest request) {
        getService().updateById(this.getParams(request, this::getUpdateParamType));
        return Result.ok();
    }

    @Api(value = ApiMethod.DELETE, method = RequestMethod.POST)
    @ResponseBody
    public Result<?> delete(HttpServletRequest request) {
        getService().remove(this.getParams(request, this::getUpdateParamType));
        return Result.ok();
    }


    @Api(value = ApiMethod.BATCH_DELETE, method = RequestMethod.POST)
    @ResponseBody
    public Result<?> batchDelete(@RequestBody Collection<? extends Serializable> ids) {
        if (ids == null || ids.isEmpty()) {
            return Result.error("ID不能为空");
        }
//        ValidationUtils.validate(ids);
        getService().removeByKeys(ids);
        return Result.ok();
    }


    protected Class<P> getSaveParamType() {
        return saveParamType;
    }

    protected Class<P> getQueryParamType() {
        return queryParamType;
    }

    protected Class<P> getUpdateParamType() {
        return updateParamType;
    }


    protected IDefaultService<T, ?> getService() {
        return CrudHelper.getCrudService(entityType);
    }

    private <O> O getParams(HttpServletRequest request, Supplier<Class<O>> supplier, Class<?>... groups) {
        O param;
        try {
            param = WebUtil.bindRequestParameter(request, supplier.get());
            ValidationUtils.validate(param, groups);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
        return param;
    }


}
